#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# just a dummy class to pull metadata from oxford Diffraction .img image file
# shamelessly hacked from CCP$ DiffractionImage
# http://www.ccp4.ac.uk/ccp4bin/viewcvs/ccp4/lib/DiffractionImage/DiffractionImageOxford.cpp?rev=1.15&content-type=text/vnd.viewcvs-markup

import struct
from string import strip
import re
REGEXP=re.compile(r"(\S+)=\s*(\S+\s+\S[^=]+(?!=)|\S*?(?=\S+=)|\S+\s*(?!\S+=))")

DEBUG = 0


class OXFORD:
  def __init__(self,file):
    self.tbufsize = 80
    self.file = file
    
  def getMetadata(self):
    meta = {}
    meta['format']   = "CRYSALIS";
    meta['manufact'] = "OXFORD-DIFFRACTION";
    meta['serialNo'] = "N/A";
    meta['version']  = '3.0'  # ?
    meta['rapidAxis'] = [1,0,0]
    meta['slowAxis'] = [0,-1,0]
    meta['serialNo'] = "N/A";
    meta['twoTheta'] = 0
    meta['scanaxis'] = -1
    buf1 = self.file.readline()
    if not buf1.startswith("OD "):
      raise Exception("File is not Oxford Diffraction .img format")
    if buf1[3] == 'R':  # for 'Ruby' detector
       meta['pixelX'] = 0.048
       meta['pixelY'] = 0.048
    elif buf1[3] == 'S' and buf1[13]=='3':  # for sapphire 3 who has 0.03 
       meta['pixelX'] = 0.03
       meta['pixelY'] = 0.03
    else:    # The other detectors, Onyx and Sapphire have a pixel size of 0.06
       meta['pixelX'] = 0.06
       meta['pixelY'] = 0.06
    if DEBUG:
      print buf1
    header= []
    for i in range(4):
      header.append(REGEXP.findall(self.file.readline().rstrip()))
    buf = self.file.read(80)
    header.append(REGEXP.findall(buf))
    if DEBUG:
      print header
#    print buf
    if ord(buf[-1]) != 26:    # last char is ctrl-z 
       print "bugger", ord(buf[-1])

    meta['width'] = int(header[1][0][1]) # NX
    meta['height'] = int(header[1][1][1]) # NY
    originalHeaderLength= int(header[2][0][1])
    NG= int(header[2][1][1])
    NS= int(header[2][2][1])
    NK= int(header[2][3][1])
    headblk =  NG+NS+NK
    meta['headblk'] = headblk
    # raise Exception(".sfrm file parsing error")

     
    """
    Types from the struct docs:
 Format C Type Python Notes
 x pad byte no value 
 c char string of length 1 
 b signed char integer 
 B unsigned char integer 1 byte
 h short integer (2 bytes)
 H unsigned short integer (2 bytes)
 i int integer 4 bytes
 I unsigned int long 4 bytes
 l long integer 
 L unsigned long long 
 q long long long (1)
 Q unsigned long long long (1)
 f float float 4 bytes
 d double float 8 bytes
 s char[] string 
 p char[] string 
 P void * integer
    """
    Nbytes = (NG+NS+NK)
    if DEBUG:
      print Nbytes
    t= {'short':'h','double':'d' ,'int':'i','float':'f'  }
    t1= {'h':2,'d':8 ,'i':4,'f':4  }
    record= [('h', 2),       # 0 short 2 * 2 bytes   
             ('h', 2),       # 1 short pad to double
             ('d',(NG-(2+2)*2)/8), # 2 end of NG
             ('d',(NS)/8),   # 3 end of NS
             ('d', 35),      # 4 NG+NS +71*4
             ('i', 16),      # 5 NG+NS +81*4  = 81+6 - 71
             ('d',(NK-(35*8+16*4))/8)  # 6 end of NK double
    ]
    format=""
    index =[0]
    bytes =[0]
    for typ,num in record:
       format=format+str(num)+typ
       index.append(index[-1]+num)
       bytes.append(bytes[-1] + t1[typ]*num)

    if DEBUG:
      print format
    buf = self.file.read(Nbytes)
    magic = struct.unpack("<"+format, buf) # little endian?

    if DEBUG:
      for i in range(len(index)-1):
        print magic[index[i] :index[i+1]] 
      print record
      print index
      print bytes
    meta['pixelX'] = meta['pixelX'] * magic[0]
    meta['pixelY'] = meta['pixelY'] * magic[1]
    meta['exposureTime'] = magic[ index[3] + 60]

    shift= (35+16/2)
    meta['mulfactor']    = magic[ index[6] + 46-shift] 
    meta['wavelength']   = magic[ index[6] + 73-shift] 
    meta['beamX']        = magic[ index[6] + 83-shift] #  NG+NS + 83*8
    meta['beamY']        = magic[ index[6] + 84-shift] #  NG+NS + 84*8
    meta['distance']     = magic[ index[6] + 89-shift] 
    meta['beamX']        = meta['beamX'] *meta['pixelX']
    meta['beamY']        = meta['beamY'] *meta['pixelY']

    scanaxis = 6
    startangles = [0.,0.,0.,0.,0.,0.]
    endangles   = [0.,0.,0.,0.,0.,0.]
    for i in range(6):
       startangles[i]= magic[ index[5]+ 0 + i ] # float 
       endangles[i]  = magic[ index[5]+10 + i ] # float
       if startangles[i] != endangles[i]:
           scanaxis=i
    """   
       startangles[i]= (NG+NS)/4 +71+i   # int
       endangles[i]  = (NG+NS)/4 +81+i   # int
    """


    oscAxes =["omega","theta","kappa / chi","phi","omega'","theta'","unknown"]
    oscAxis= oscAxes[scanaxis]

    RADTODEG = 180.0/3.141592627
    if scanaxis != 6:
      meta['oscEnd']   =   endangles[scanaxis] * RADTODEG * meta['mulfactor']
      meta['oscStart'] = startangles[scanaxis] * RADTODEG * meta['mulfactor']
                        
    for i in range(6):
       startangles[i]= startangles[i] * RADTODEG * meta['mulfactor']
       endangles[i]= endangles[i] * RADTODEG * meta['mulfactor']

    meta['oscAxis']     = oscAxis
    meta['scanaxis']    = scanaxis
    meta['startangles'] = startangles
    meta['endangles']   = endangles
    return meta

	
if __name__ == '__main__':
   import sys
   fileList = sys.argv[1:]
   print fileList
   for arg in fileList:
     print arg
     file= open(arg,'rb')
     sf = OXFORD(file)
     meta =  sf.getMetadata()
     file.close()
     for key in meta.keys():
       print "%7s : %s" % (key,meta[key])

